{
 "cells": [
  {
   "cell_type": "markdown",
   "id": "a5370ae1-8d6f-4412-a3d3-21185f36f9fa",
   "metadata": {},
   "source": [
    "# 装饰器\n",
    "## 装饰器的概念\n",
    "装饰器本质上是一个Python函数，它可以在不改动其他函数的前提下，对函数功能进行扩充，通常情况下，装饰器可以用于不同场景：\n",
    "- 引入日期\n",
    "- 函数执行的时间统计\n",
    "- 执行函数前的预处理\n",
    "- 执行函数后的清理功能\n",
    "- 权限校验"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "id": "d85c5f7f-bbe4-40ff-b18e-aff6dd69a8ca",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "func_one\n"
     ]
    }
   ],
   "source": [
    "# coding:UTF-8\n",
    "def func_one():\n",
    "    print('func_one')\n",
    "\n",
    "# 调用该函数\n",
    "func_one()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "e24246b8-b2b0-4e99-8e94-1e988536b52c",
   "metadata": {},
   "source": [
    "现在有一个需求，希望可以在函数中输一句话，用于记录函数正在执行"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "id": "7333d65d-280e-4d67-9046-6d7fae5783cc",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "func_one\n",
      "func_one is running\n"
     ]
    }
   ],
   "source": [
    "# coding:UTF-8\n",
    "def func_one():\n",
    "    print('func_one')\n",
    "    print('func_one is running')\n",
    "\n",
    "# 调用函数\n",
    "func_one()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "094cdbd7-bb39-4345-a6b0-0ae7cbe91c92",
   "metadata": {},
   "source": [
    "因为此时如果通过这样的方式实现则会显得比较麻烦，因为在实际开发中还需要编写逻辑的代码，为了减少代码的重复，记录日志，则使用装饰器\n",
    "装饰器就是为了满足上述需求，在Python中，装饰器的语法是以@ 开头"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "id": "449fa863-3b5c-4636-a17d-c2233fa93d21",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "  正在装饰  \n",
      "  正在验证权限  \n",
      "test\n"
     ]
    }
   ],
   "source": [
    "def wrapper(func):\n",
    "    print('  正在装饰  ')\n",
    "    def inner():\n",
    "        print('  正在验证权限  ')\n",
    "        func()\n",
    "    return inner\n",
    "\n",
    "@wrapper    #添加装饰器\n",
    "def test():\n",
    "    print(\"test\")\n",
    "\n",
    "test()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "8033b4ca-cf0c-4073-b920-63abb0a87c95",
   "metadata": {},
   "source": [
    "## 多个装饰器\n",
    "多个装饰器可以应用在一个函数上面，他们的执行是自下而上的"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "id": "663c1048-24ff-48fb-84b3-8cf2b5a96344",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      ".....正在装饰2.....\n",
      ".....正在装饰.....\n"
     ]
    }
   ],
   "source": [
    "# coding:UTF-8\n",
    "# 【很重要】引用传递\n",
    "\n",
    "def wrapper_one(func):\n",
    "    print('.....正在装饰.....')\n",
    "\n",
    "    def inner():\n",
    "        print('.....正在验证权限.....')\n",
    "        func()\n",
    "    return inner\n",
    "\n",
    "def wrapper_two(func):\n",
    "    print('.....正在装饰2.....')\n",
    "\n",
    "    def inner():\n",
    "        print('.....正在验证权限2.....')\n",
    "        func()\n",
    "    return inner\n",
    "\n",
    "# 定义装饰器\n",
    "@wrapper_one\n",
    "@wrapper_two\n",
    "def test():\n",
    "    print('.....test.....')\n",
    "\n",
    "#此时哪怕不调用函数，只要有装饰器，那么它也会输出，到那时不会输出装饰器的函数test()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "47acd6e7-4130-43ef-8309-3e1fa69f1981",
   "metadata": {},
   "source": [
    "## 装饰器对有参函数进行装饰\n",
    "之前的装饰器都是对无参函数的装饰，如果要对有参函数进行装饰，就需要注意参数了"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "id": "58acc26c-ecfb-4e23-88b9-2ddb0912a4d2",
   "metadata": {},
   "outputs": [
    {
     "ename": "TypeError",
     "evalue": "wrapper.<locals>.inner() takes 0 positional arguments but 2 were given",
     "output_type": "error",
     "traceback": [
      "\u001b[1;31m---------------------------------------------------------------------------\u001b[0m",
      "\u001b[1;31mTypeError\u001b[0m                                 Traceback (most recent call last)",
      "Cell \u001b[1;32mIn[2], line 13\u001b[0m\n\u001b[0;32m     10\u001b[0m     \u001b[38;5;28mprint\u001b[39m(\u001b[38;5;124m'\u001b[39m\u001b[38;5;124ma = \u001b[39m\u001b[38;5;132;01m%d\u001b[39;00m\u001b[38;5;124m, b = \u001b[39m\u001b[38;5;132;01m%d\u001b[39;00m\u001b[38;5;124m'\u001b[39m \u001b[38;5;241m%\u001b[39m (a, b))\n\u001b[0;32m     12\u001b[0m \u001b[38;5;66;03m#调用有参函数test\u001b[39;00m\n\u001b[1;32m---> 13\u001b[0m test(\u001b[38;5;241m1\u001b[39m,\u001b[38;5;241m2\u001b[39m)\n",
      "\u001b[1;31mTypeError\u001b[0m: wrapper.<locals>.inner() takes 0 positional arguments but 2 were given"
     ]
    }
   ],
   "source": [
    "# coding:UTF-8\n",
    "def wrapper(func):\n",
    "    def inner():\n",
    "        print('     开始校验权限     ')\n",
    "        func()    # 引用传递\n",
    "    return inner\n",
    "\n",
    "@wrapper    # 注解后的名称是随着编写的函数名而变化的\n",
    "def test(a, b):\n",
    "    print('a = %d, b = %d' % (a, b))\n",
    "\n",
    "#调用有参函数test\n",
    "test(1,2)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "3900a7d4-5243-49fe-8ce9-8881ec91f350",
   "metadata": {},
   "source": [
    "此时如果无法确定参数的情况下，我们可以使用可变参数来传递"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "id": "2c2d4be8-1956-4c1c-8a8c-1c2fb8da5830",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "    开始验证权限    \n",
      ".....test.....\n"
     ]
    }
   ],
   "source": [
    "# coding:UTF-8\n",
    "\n",
    "def wrapper(func):\n",
    "    def inner(*args, **kwargs):\n",
    "        print('    开始验证权限    ')\n",
    "        func(*args, **kwargs)\n",
    "\n",
    "    return inner\n",
    "\n",
    "@wrapper    #注解后的名称是随着编写的函数名而变化的\n",
    "def test(*args, **kwargs):\n",
    "    print('.....test.....')\n",
    "\n",
    "#调用有参函数test\n",
    "test(1, 2)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "04f95b10-2ffa-43e5-932e-48e3b0491683",
   "metadata": {},
   "outputs": [],
   "source": [
    "# coding:UTF-8\n",
    "\n",
    "def func(function_name):\n",
    "    def func_in():\n",
    "        return function_name()    #一定要加上括号\n",
    "\n",
    "    return func_in\n",
    "\n",
    "@wrapper    # 注解后的名称是随着编写的函数名而变化的\n",
    "def test(a, c):\n",
    "    return 'Python协议'"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3 (ipykernel)",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.12.4"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
